
static struct proc_dir_entry *lcdmod_procdir, *lcdmod_procfile, 
	*lcdmod_long_procfile, *lcdmod_all_procfile;

/* proc tree functions */
/* proc_read_lcdmod()
 * if data == NULL -  reading from /proc/lcdmod/lcdmod
 * if data == state - reading from /proc/lcdmod/lcdmod_long
 * if data == lcddev - reading from /proc/lcdmod/lcdmod_all
 */
static int proc_read_lcdmod(char *buffer, char **start, off_t offset, int size, int *eof, void *data )
{
	char *temp = buffer;
	int i, j;

	temp += sprintf(temp, /* I/O base */
		"I/O base:        %#8lx\n"
		, 
		lcddev.pd->port->base);
	if(data != NULL) { /* print counters information - _long and _all */
		temp += sprintf( temp, 
			" ^ NumReset:   %10lu\n"
			" ^ NumNext:    %10lu\n"
			" ^ NumEnable:  %10lu\n"
			" ^ ^ Reads:    %10lu\n"
			" ^ ^ Writes:   %10lu\n"
			" ^ ^ BfChecks: %10lu\n"
			,
			lcddev.reset_num,
			lcddev.next_num,
			lcddev.bfchecks_num+lcddev.read_num+lcddev.write_num,
			lcddev.read_num,
			lcddev.write_num,
			lcddev.bfchecks_num);
		if(data == &lcddev) { /* print flags and controlers specyfiuc informations - only _all*/
			temp += sprintf( temp, 
				" ^ Flags:        %#08lx\n"
				" ^ ^ CheckingBF:     %4s\n"
				" ^ ^ was IRQ:        %4s\n"
				,
				lcddev.flags,
				( test_bit(FLAG_NOBFCHECK, &lcddev.flags) ? "no" : "yes" ),
				( test_bit(FLAG_WAS_IRQ, &lcddev.flags) ? "yes" : "no" ));
			for ( j = 0; j < NUM_CONTROLLERS; j++) {
				int k, l;
				temp += sprintf( temp, "Controler number %d\n", j);
				for (k = 0; k < 8; k++) {
					temp += sprintf( temp, " ^ CGRAM[%1d]: ", k);
					for (l=0; l<8; l++) { 
						temp += sprintf(temp, "%02x", lcddev.lcd[j].cgram[k][l]);
					}
					temp += sprintf(temp, "\n");
				}
				temp += sprintf(temp, 
					" ^ cursor pos row col : %2d %2d\n"
					" ^ errors: %2d\n"
					,
					lcddev.lcd[j].cur_row,
					lcddev.lcd[j].cur_col, 
					lcddev.lcd[j].errors_num);
			}
		}
	}

	temp += sprintf(temp,
			"DisplayRows:         %4d\n"
			"DisplayColumns:      %4d\n"
			"Linewrap:            %4s\n"
			"ControlersPerPort:   %4d\n"
			,
			DISP_ROWS, 
			DISP_COLS,
			(test_bit(FLAG_WRAP_OFF, &(lcddev.flags)) ? "yes" : "no"),
			NUM_CONTROLLERS );
			
	if (data == &lcddev) {
		temp += sprintf(temp, 
			"RowsPerControler:    %4d\n"
			"Current virtual cursor position: %2d %2d\n"
			,
			ROWS_PER_CTRL,
			row, col);
	}
	
	/* Print display state */
	temp += sprintf( temp, "+" );
	for( i = 0; i < DISP_COLS; i++ )
		temp += sprintf( temp, "-" );
	temp += sprintf( temp, "+" );
	if (data == &lcddev)
		temp += sprintf(temp, " ctrl_nr ");
	temp += sprintf( temp, "\n");
	
	mutex_lock(&state_mutex);
	for( i = 0; i < DISP_ROWS ; i++ ) {
		temp += sprintf( temp, "|" );
		for( j = 0; j < DISP_COLS ; j++ ) {
			if ( state[i][j] < 10 ) /* character from CGRAM */
				temp += sprintf( temp, "^");
			else
				temp += sprintf( temp, "%c", state[i][j]);
		}
		if (data == &lcddev)
			temp += sprintf(temp, "| %d \n", (i / ROWS_PER_CTRL));
		else
			temp += sprintf( temp, "|\n");
	}
	mutex_unlock(&state_mutex);

	temp += sprintf( temp, "+" );
	for( i = 0; i < DISP_COLS; i++ )
			temp += sprintf( temp, "-" );
	temp += sprintf( temp, "+\n" );
	return temp - buffer;
}

static int lcdmod_proc_init(void)
{
	lcdmod_procdir = proc_mkdir("lcdmod", NULL);
	if(lcdmod_procdir == NULL) {
		PERR("Cannot crate proc directory entry.\n");	
		goto fail_proc_mkdir;
	}
	lcdmod_procfile = create_proc_entry("lcdmod", 0444, lcdmod_procdir);
	if(lcdmod_procfile == NULL) {
		PERR("Cannot create /proc/lcdmod/lcdmod entry.\n");
		goto fail_proc_lcdmod;
	}
	lcdmod_procfile->data = NULL;
	lcdmod_procfile->read_proc = proc_read_lcdmod;
	lcdmod_procfile->write_proc = NULL;
	lcdmod_long_procfile = create_proc_entry("lcdmod_long", 0444, lcdmod_procdir);
	if(lcdmod_long_procfile == NULL) {
		PERR("Cannot create /proc/lcdmod/lcdmod_long entry.\n");
		goto fail_proc_lcdmod_long;
	}
	lcdmod_long_procfile->data = state;
	lcdmod_long_procfile->read_proc = proc_read_lcdmod;
	lcdmod_long_procfile->write_proc = NULL;	
	lcdmod_all_procfile = create_proc_entry("lcdmod_all", 0444, lcdmod_procdir);
	if(lcdmod_all_procfile == NULL) {
		PERR("Cannot create /proc/lcdmod/lcdmod_long entry.\n");
		goto fail_proc_lcdmod_all;
	}
	lcdmod_all_procfile->data = &lcddev;
	lcdmod_all_procfile->read_proc = proc_read_lcdmod;
	lcdmod_all_procfile->write_proc = NULL;
	
	return 0; /* succes */
	
	/* remove_proc_entry("lcdmod_all", lcdmod_procdir); */
fail_proc_lcdmod_all:
	remove_proc_entry("lcdmod_long", lcdmod_procdir);
fail_proc_lcdmod_long:
	remove_proc_entry("lcdmod",lcdmod_procdir);
fail_proc_lcdmod:
	remove_proc_entry("lcdmod", NULL);
fail_proc_mkdir:
	return(-1);
}

static void lcdmod_proc_exit(void)
{
	remove_proc_entry("lcdmod_all", lcdmod_procdir);
	remove_proc_entry("lcdmod_long", lcdmod_procdir);
	remove_proc_entry("lcdmod", lcdmod_procdir);
	remove_proc_entry("lcdmod", NULL);
}
